#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#include "defs.h"
#include "cpu.h"
#include "rv32.h"
#include "err.h"

int
rv32i_tell (int32 inst) {
    if (inst == 0) {
        printf ("EMPTY INST.\n");
        return 0;
    }
    IR = inst;
    if (OPCODE != 0x33) goto L1;
    DEF_R_INST (ADD, 0x0, 0x0, 0x33,{});
    DEF_R_INST (SUB, 0x20, 0x0, 0x33,{});
    DEF_R_INST (AND, 0x0, 0x7, 0x33, {});
    DEF_R_INST (OR, 0x0, 0x6, 0x33, {});
    DEF_R_INST (XOR, 0x0, 0x4, 0x33, {});
    DEF_R_INST (SLL, 0x0, 0x1, 0x33, {});
    DEF_R_INST (SRL, 0x0, 0x5, 0x33, {});
    DEF_R_INST (SRA, 0x20, 0x5, 0x33, {});
    DEF_R_INST (SLT, 0x0, 0x2, 0x33, {});
    DEF_R_INST (SLTU, 0x0, 0x3, 0x33, {});
    L1:
    if (OPCODE != 0x13) goto L2;
    DEF_I_INST (ADDI, 0x0, 0x13, {});
    DEF_I_INST (ANDI, 0x7, 0x13, {});
    DEF_I_INST (ORI, 0x6, 0x13, {});
    DEF_I_INST (XORI, 0x4, 0x13, {});
    DEF_I_SP_INST (SLLI, 0x0, 0x1, 0x13, {});
    DEF_I_SP_INST (SRLI, 0x0, 0x5, 0x13, {});
    DEF_I_SP_INST (SRAI, 0x20, 0x5, 0x13, {});
    DEF_I_INST (SLTI, 0x2, 0x13, {});
    DEF_I_INST (SLTIU, 0x3, 0x13, {});
    L2:
    if (OPCODE != 0x3) goto L3;
    DEF_I_INST (LB, 0x0, 0x3, {});
    DEF_I_INST (LH, 0x1, 0x3, {});
    DEF_I_INST (LW, 0x2, 0x3, {});
    DEF_I_INST (LBU, 0x4, 0x3, {});
    DEF_I_INST (LHU, 0x5, 0x3, {});
    L3:
    DEF_I_JMP_INST (JALR, 0x0, 0x67, {});
    if (OPCODE != 0x23) goto L4;
    DEF_S_INST (SB, 0x0, 0x23, {});
    DEF_S_INST (SH, 0x1, 0x23, {});
    DEF_S_INST (SW, 0x2, 0x23, {});
    L4:
    if (OPCODE != 0x63) goto L5;
    DEF_B_INST (BEQ, 0x0, 0x63, {});
    DEF_B_INST (BNE, 0x1, 0x63, {});
    DEF_B_INST (BLT, 0x4, 0x63, {});
    DEF_B_INST (BGE, 0x5, 0x63, {});
    DEF_B_INST (BLTU, 0x6, 0x63, {});
    DEF_B_INST (BGEU, 0x7, 0x63, {});
    L5:
    DEF_U_INST (LUI, 0x37, {});
    DEF_U_INST (AUIPC, 0x17, {});
    DEF_J_INST (JAL, 0x6F, {});
    printf ("Not a rv32i inst. Forwarding to next ISA ...\n");
    return -1;
    executed:
    return 0;
}

int
rv32i_exec () {
    int stat;
    stat = 0;
    if ((PC & 0x3) != 0) {
        stat |= E_CPU_PC_NOT_ALIGNED;
        goto error;
    }
    stat |= mem_phy_read (PC, &IR, 0);
    if (stat != 0) goto error;
    
    if (OPCODE != 0x33) goto L1;
    DEF_R_INST (ADD, 0x0, 0x0, 0x33,{});
    DEF_R_INST (SUB, 0x20, 0x0, 0x33,{});
    DEF_R_INST (AND, 0x0, 0x7, 0x33, {});
    DEF_R_INST (OR, 0x0, 0x6, 0x33, {});
    DEF_R_INST (XOR, 0x0, 0x4, 0x33, {});
    DEF_R_INST (SLL, 0x0, 0x1, 0x33, {});
    DEF_R_INST (SRL, 0x0, 0x5, 0x33, {});
    DEF_R_INST (SRA, 0x20, 0x5, 0x33, {});
    DEF_R_INST (SLT, 0x0, 0x2, 0x33, {});
    DEF_R_INST (SLTU, 0x0, 0x3, 0x33, {});
    L1:
    if (OPCODE != 0x13) goto L2;
    DEF_I_INST (ADDI, 0x0, 0x13, {});
    DEF_I_INST (ANDI, 0x7, 0x13, {});
    DEF_I_INST (ORI, 0x6, 0x13, {});
    DEF_I_INST (XORI, 0x4, 0x13, {});
    DEF_I_SP_INST (SLLI, 0x0, 0x1, 0x13, {});
    DEF_I_SP_INST (SRLI, 0x0, 0x5, 0x13, {});
    DEF_I_SP_INST (SRAI, 0x20, 0x5, 0x13, {});
    DEF_I_INST (SLTI, 0x2, 0x13, {});
    DEF_I_INST (SLTIU, 0x3, 0x13, {});
    L2:
    if (OPCODE != 0x3) goto L3;
    DEF_I_INST (LB, 0x0, 0x3, {});
    DEF_I_INST (LH, 0x1, 0x3, {});
    DEF_I_INST (LW, 0x2, 0x3, {});
    DEF_I_INST (LBU, 0x4, 0x3, {});
    DEF_I_INST (LHU, 0x5, 0x3, {});
    L3:
    DEF_I_JMP_INST (JALR, 0x0, 0x67, {});
    if (OPCODE != 0x23) goto L4;
    DEF_S_INST (SB, 0x0, 0x23, {});
    DEF_S_INST (SH, 0x1, 0x23, {});
    DEF_S_INST (SW, 0x2, 0x23, {});
    L4:
    if (OPCODE != 0x63) goto L5;
    DEF_B_INST (BEQ, 0x0, 0x63, {});
    DEF_B_INST (BNE, 0x1, 0x63, {});
    DEF_B_INST (BLT, 0x4, 0x63, {});
    DEF_B_INST (BGE, 0x5, 0x63, {});
    DEF_B_INST (BLTU, 0x6, 0x63, {});
    DEF_B_INST (BGEU, 0x7, 0x63, {});
    L5:
    DEF_U_INST (LUI, 0x37, {});
    DEF_U_INST (AUIPC, 0x17, {});
    DEF_J_INST (JAL, 0x6F, {});
    stat |= E_CPU_BAD_OP;
    goto error;
    executed:
    return stat;
    error:
    return stat;
}